home *** CD-ROM | disk | FTP | other *** search
/ STraTOS 1997 April & May / STraTOS 1 - 1997 April & May.iso / CD01 / INTERNET / SITES / RAND / DVIEW000.LZH / VIEW.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-10  |  13.2 KB  |  550 lines

  1. #define C
  2.  
  3. #undef PROFILE
  4. #define COUNT
  5.  
  6. /********************************************************************
  7.  FILENAME: VIEW.CPP
  8.  AUTHOR  : JAKE HILL
  9.  DATE    : 12/1/94
  10.  
  11.  Copyright (c) 1994 by Jake Hill:
  12.  If you use any part of this code in your own project, please credit
  13.  me in your documentation and source code.  Thanks.
  14. ********************************************************************/
  15.  
  16. #include "view.h"
  17. #include "trig.h"
  18.  
  19. #ifdef __GNUC__
  20.   #include <osbind.h>
  21.   #include <memory.h>
  22. #else
  23.   #include <tos.h>
  24. #endif
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29.             
  30. #define SKY_COLOR       1
  31. #define FLOOR_COLOR     2
  32. #define WALL_COLOR      3
  33. #define RED_COLOR       4
  34. #define LEDGE_COLOR     5
  35. #define ZMIN            20L  
  36.  
  37. #define UPPER_TYPE      0
  38. #define WALL_TYPE       1
  39. #define LOWER_TYPE      2
  40.  
  41. #ifdef C
  42. extern char hash(side *, int);
  43. extern char OnRightNode(short node_num);
  44. extern char OnRightLine(short from, short to);
  45. extern char LeftSideInCone(short node_num);
  46. extern char RightSideInCone(short node_num);
  47. extern void draw_line(short, short, short);
  48. void DrawNode(short node_num);
  49. void DrawSSector(short SS);
  50. #ifdef __GNUC__
  51. void LoadSeg(short seg);
  52. #else
  53. void LoadSeg(short xseg);
  54. #endif
  55. void AddWall(short sx1, short sx2, short Rb, short Rt, short Rfz, short Rtz);
  56. extern void DrawSegs(void);
  57. #if 0
  58. void AddFloorUp(short lb, short b, short start, short type);
  59. void AddFloorDown(short lb, short b, short start, short type);
  60. void EndFloorUp(short lb, short b, short end);
  61. void EndFloorDown(short lb, short b, short end);
  62. #endif
  63. #endif
  64.  
  65. extern short width;
  66. extern short height;
  67.  
  68. extern short flooropt;
  69. extern short floorcol;
  70. extern short nofloor;
  71. extern short wallopt;
  72. extern short wallcol;
  73. extern short singlestep;
  74. extern short showdata;
  75. extern short draw_2D;
  76.  
  77. #ifdef COUNT
  78. extern long drawview;
  79.  
  80. extern long addfloor;
  81. extern long addfloor_loops;
  82.  
  83. extern long addwall;
  84. extern long addwall_loops;
  85.  
  86. extern long coldraw;
  87. extern long coldraw_loops;
  88.  
  89. extern long rowdraw;
  90. extern long rowdraw_loops;
  91.  
  92. extern long drawnode;
  93. extern long drawssector;
  94. extern long drawssector_loops;
  95. extern long loadseg;
  96. extern long loadseg_loops1;
  97. extern long loadseg_loops2;
  98.  
  99. extern long setuptime;
  100. extern long drawtime;
  101. extern long c2ptime;
  102. #endif
  103.  
  104. /* These are some yucky global variables.  They should probably
  105.  * be moved into the class's member data.
  106.  */
  107. extern short ColCount;
  108. extern short WallCount;
  109. extern short WallRunCount;
  110. extern short FirstSSector;
  111.  
  112. #if 0
  113. extern short player_ssector;
  114. #endif
  115.  
  116. /* Elements of this array indicate if a screen column is completely drawn. */
  117.  
  118. #if 0
  119. extern short     Col_Done[320];
  120. #endif
  121. extern char      Col_Done[320];    /* Slightly better for the cache */
  122.  
  123.  
  124. /* Elements of this array hold indexes into the wall_run array. */
  125.  
  126. #if 1
  127. extern short     intersections[50][320];
  128. #endif
  129.  
  130. /* The number of wall_runs visible on a particular screen column. */
  131.  
  132. #if 1
  133. extern short     int_count[320];
  134. #endif
  135.  
  136. /* MaxY & MinY are the active edge lists for the top & bottom of the screen. */
  137.  
  138. extern short     MaxY[320];
  139. extern short     MinY[320];
  140.  
  141.  
  142. /* This is the wall_run array.  It contains all of the wall_runs which
  143.  * are visible in a single frame.
  144.  */
  145.  
  146. #if 1
  147. extern wall_run  walls[8000];  /* 320*50 = 16000 */
  148. #endif
  149.  
  150. extern short walltop[320];
  151. extern short wallbottom[320];
  152.  
  153. /* The next two arrays are used for both floors and ceilings.
  154.  * Elements of this array hold indexes into the floor_run array.
  155.  */
  156.  
  157. #if 1
  158. extern floor_run floorlist[200][40];
  159. #endif
  160.  
  161. extern short floorlst[200];
  162. extern short floortex[200];
  163.  
  164. /* The number of floor_runs visible on a particular screen column. */
  165.  
  166. extern short     runcount[200];
  167.  
  168.  
  169. /* The offscreen buffer. */
  170. extern char *screenbuf;
  171.  
  172.  
  173. extern void c2p(char *buf, int w_area, int h_area);
  174. extern char hash(side *ThisSide, int wall_type);
  175. extern long get_timer(void);
  176.  
  177. void DrawNode(short node_num)
  178. {
  179. #ifdef COUNT
  180.    drawnode++;
  181. #endif
  182.  
  183. /* If this node is a SSECTOR then we need to render it. */
  184.  
  185.    if (node_num & 0x8000) {
  186.       DrawSSector(node_num & 0x7fff);
  187.       return;
  188.    }
  189.  
  190. /* Once we have rendered 319 columns then we are done,
  191.  * so lets stop recursing.
  192.  */
  193.  
  194.    if (ColCount > width - 2)
  195.       return;
  196.  
  197.    if (!OnRightNode(node_num)) {
  198.       if (LeftSideInCone(node_num))
  199.          DrawNode(PNode_Array[node_num]->left);
  200.       if (RightSideInCone(node_num))
  201.          DrawNode(PNode_Array[node_num]->right);
  202.    } else {
  203.       if (RightSideInCone(node_num))
  204.          DrawNode(PNode_Array[node_num]->right);
  205.       if (LeftSideInCone(node_num))
  206.          DrawNode(PNode_Array[node_num]->left);
  207.    }
  208. }
  209.  
  210.  
  211. /* This function obtains data common to all segs in the SSector
  212.  * as well as doing the backface elimination via OnRight.
  213.  */
  214.  
  215. void DrawSSector(short SS)
  216. {
  217.    short i;
  218.    short LineSide, Sector;
  219.    short SegCount, FirstSeg;
  220.    segment *ThisSeg;
  221.    sector  *ThisSector;
  222.  
  223. /* Load FirstSeg and SegCount locally for speed improvement. */
  224.  
  225.    FirstSeg = SSector_Array[SS].first_seg;
  226.    SegCount = SSector_Array[SS].num_segs;
  227.  
  228. #ifdef COUNT
  229.    drawssector++;
  230.    drawssector_loops += SegCount;
  231. #endif
  232.  
  233.    ThisSeg = &Seg_Array[FirstSeg];
  234.  
  235.    LineSide = ThisSeg->line_side;
  236.  
  237. #ifdef __GNUC__
  238.    Sector   = Side_Array[Line_Array[ThisSeg->line].side[LineSide]].sector;
  239. #else
  240.    Sector   = Side_Array[Line_Array[ThisSeg->xline].side[LineSide]].sector;
  241. #endif
  242.  
  243. /* Load the floor and ceiling height. */
  244.  
  245.    ThisSector = &Sector_Array[Sector];
  246.    floor_ht   = ThisSector->floor_ht;
  247.    ceiling_ht = ThisSector->ceiling_ht;
  248.  
  249. /* Here we determine the viewers height relative to all the walls, etc. */
  250.  
  251.    if (FirstSSector) {
  252.       FirstSSector = 0;
  253.       Pz = Ph + floor_ht;
  254. #if 0
  255. /* ThisSector might be better below */
  256.       player_ssector = SS;    /* Used to stop wall pass-through */
  257. #endif
  258.    }
  259.  
  260. /* Draw each SEG in the SSECTOR which can be seen. */
  261.  
  262.    for (i = 0;i < SegCount;i++) {
  263.       if (OnRightLine(ThisSeg->from, ThisSeg->to)) {
  264. if (!draw_2D || wallcol)
  265.          LoadSeg(FirstSeg + i);
  266. else
  267.    draw_line(ThisSeg->from, ThisSeg->to, 0xff);
  268.       }
  269.       ThisSeg++;
  270.    }
  271. }
  272.  
  273.  
  274. /* This function is where all of the Rotations and Transformations
  275.  * are done.  This is my very first 3D program, so there is probably
  276.  * a LOT here which can be optimized for speed.
  277.  */
  278.  
  279. #ifdef __GNUC__
  280. void LoadSeg(short seg)
  281. #else
  282. void LoadSeg(short xseg)
  283. #endif
  284. {
  285. #ifdef __GNUC__
  286.    segment *ThisSeg = &Seg_Array[seg];
  287. #else
  288.    segment *ThisSeg = &Seg_Array[xseg];
  289. #endif
  290.    short To = ThisSeg->to;
  291.    short From = ThisSeg->from;
  292.    unsigned short Angle = ThisSeg->angle - Pangle;
  293.    char ch;
  294.    vertex *Vertex;
  295.    short Wfx, Wfy;
  296.    short Wtx, Wty;
  297.    long Rfz, Rtz;
  298.    long Rfx, Rtx;
  299.    long TanAngle;
  300.    long XZ;
  301.    short x1, x2, sx1, sx2;
  302.    char ExitNow;
  303.    int x;
  304.    short Rt, Rb;
  305.    short SingleSided;
  306.    short Side;
  307.    line *ThisLine;
  308.    side *ThisSide, *ThatSide;
  309.  
  310. #ifdef COUNT
  311.    loadseg++;
  312. #endif
  313.  
  314. /* Store the World Space Coordinates */
  315.  
  316.    Vertex = &Vertex_Array[To];
  317.    Wtx = Vertex->x;
  318.    Wty = Vertex->y;
  319.  
  320.    Vertex = &Vertex_Array[From];
  321.    Wfx = Vertex->x;
  322.    Wfy = Vertex->y;
  323.  
  324. /* Rotate the World Space Coordinates relative to player. */
  325.  
  326.    Rfz = (((Wfx - Px) * CosPangle) - ((Wfy - Py) * SinPangle)) >> 16;
  327.    Rtz = (((Wtx - Px) * CosPangle) - ((Wty - Py) * SinPangle)) >> 16;
  328.  
  329. /* If the seg is completely behind the player, exit the fn. */
  330.  
  331.    if ((Rfz < ZMIN) && (Rtz < ZMIN)) {
  332.       if (draw_2D)
  333.          draw_line(From, To, 1);
  334.       return;
  335.    }
  336. /* Finish rotating the coordinates. */
  337.  
  338.    Rfx = (((Wfx - Px) * SinPangle) + ((Wfy - Py) * CosPangle)) >> 16;
  339.    Rtx = (((Wtx - Px) * SinPangle) + ((Wty - Py) * CosPangle)) >> 16;
  340.  
  341. /* Perform Z-clipping if necessary. */
  342.  
  343.    TanAngle = tangent(Angle);
  344.  
  345. #if 0
  346. if (ch != 'x') {
  347.    if (Rfx > Rfz) {     /* Clip Rfx, Rfz to line x = z. */
  348. if (wallopt && flooropt && (ch == 's')) {
  349.       printf("Clip Rfx/z to x = z\n");
  350. }
  351.       if (TanAngle == 65536L)  /* Prevent a divide by zero. */
  352.          return;
  353.       long XZ = ((Rfx << 16) - (Rfz * TanAngle)) / (65536L - TanAngle);
  354.       Rfx = Rfz = XZ;
  355.    }
  356. /* Just a test below */
  357.    if (Rtx > Rtz) {     /* Clip Rtx, Rtz to line x = z. */
  358. if (wallopt && flooropt && (ch == 's')) {
  359.       printf("Clip Rtx/z to x = z\n");
  360. }
  361.       if (TanAngle == 65536L)  /* Prevent a divide by zero. */
  362.          return;
  363.       XZ = ((Rtx << 16) - (Rtz * TanAngle)) / (65536L - TanAngle);
  364.       Rtx = Rtz = XZ;
  365.    }
  366. }
  367. #endif
  368.    if (Rfz < ZMIN) {    /* Clip Rfx, Rfz to zmin. */
  369. if (wallopt && flooropt && (ch == 's')) {
  370.       printf("Clip Rfx/z to ZMIN\n");
  371. }
  372.       Rfx = Rfx + (((ZMIN - Rfz) * TanAngle) >> 16);
  373.       Rfz = ZMIN;
  374.    }
  375.    if (Rtz < ZMIN) {    /* Clip Rtx, Rtz to zmin. */
  376. if (wallopt && flooropt && (ch == 's')) {
  377.       printf("Clip Rtx/z to ZMIN\n");
  378. }
  379.       Rtx = Rtx + (((ZMIN - Rtz) * TanAngle) >> 16);
  380.       Rtz = ZMIN;
  381.    }
  382.  
  383.    if (Rfz > 9999L) {   /* We don't want to go out of */
  384.       Rfz = 9999L;
  385. if (wallopt && flooropt && (ch == 's')) {
  386.       printf("Clipping Rfz\n");
  387. }
  388.    }
  389.    if (Rtz > 9999L) {   /* bounds with these values. */
  390.       Rtz = 9999L;
  391. if (wallopt && flooropt && (ch == 's')) {
  392.       printf("Clipping Rtz\n");
  393. }
  394.    }
  395.  
  396. /* Project the World Space -X- Coordinates to screen space coordinates.
  397.  * MAKE SURE that Z-Clipping is done before this or we may get a
  398.  * negative value for Rfz or Rtz - this would be out of bounds.
  399.  */
  400.  
  401.    sx1 = x1 = (short)((long)width / 2 - ((Rfx * invdistance(Rfz)) >> 16));
  402.    sx2 = x2 = (short)((long)width / 2 - ((Rtx * invdistance(Rtz)) >> 16));
  403.  
  404. /* Check if wall segment is on screen or is wide enough to see. */
  405.  
  406.    if (sx2 <= 0) {
  407. #if 0
  408.       if (sx2 == 0)
  409.          printf("sx2 <= 0\n");
  410. #endif
  411.       if (draw_2D)
  412.          draw_line(From, To, 2);
  413.       return;
  414.    }
  415.    if (sx1 > width - 1) {
  416.       if (draw_2D)
  417.          draw_line(From, To, 2);
  418.       return;
  419.    }
  420.    if (sx1 == sx2) {
  421. #if 0
  422.       printf("sx1 == sx2\n");
  423. #endif
  424.       if (draw_2D)
  425.          draw_line(From, To, 2);
  426.       return;
  427.    }
  428.  
  429. /* Check if wall segment is completely occluded. */
  430.  
  431.    if (x1 < 0)
  432.       x1 = 0;
  433.    if (x2 > width)
  434.       x2 = width;
  435.  
  436.    ExitNow = 1;
  437.    for(x = x1;x < x2;x++)
  438.       if (Col_Done[x] == 0) {
  439.          ExitNow = 0;
  440.          break;
  441.       }
  442. #ifdef COUNT
  443.    loadseg_loops1 += x - x1;
  444. #endif
  445.  
  446.    if (ExitNow) {
  447.       if (draw_2D)
  448.          draw_line(From, To, 3);
  449.       return;
  450.    }
  451. if (singlestep) {
  452.    ch = Cnecin();
  453. }
  454.  
  455.    if (draw_2D)
  456.       draw_line(From, To, 0xff);
  457.  
  458. if (singlestep && (ch == 'c')) {
  459.    printf("2D (%d,%d) -> (%d,%d)\n", Wfx, Wfy, Wtx, Wty);
  460.    printf("Z  %ld -> %ld\n", Rfz, Rtz);
  461.    printf("X  %ld -> %ld  (%d->%d)\n", Rfx, Rtx, x1, x2);
  462.    printf("MaxY[%d] = %d, MinY[%d] = %d\n", x1, MaxY[x1], x1, MinY[x1]);
  463.    printf("MaxY[%d] = %d, MinY[%d] = %d\n", x2, MaxY[x2], x2, MinY[x2]);
  464. }
  465.  
  466. /**************************************************************
  467.  * Calculate the screen coordinates of the wall segment.
  468.  **************************************************************/
  469.  
  470. #ifdef __GNUC__
  471.    SingleSided = !(Line_Array[ThisSeg->line].flags & 0x0004);
  472. #else
  473.    SingleSided = !(Line_Array[ThisSeg->xline].flags & 0x0004);
  474. #endif
  475.  
  476.    Side = ThisSeg->line_side;
  477. #ifdef __GNUC__
  478.    ThisLine = &Line_Array[ThisSeg->line];
  479. #else
  480.    ThisLine = &Line_Array[ThisSeg->xline];
  481. #endif
  482.    ThisSide = &Side_Array[ThisLine->side[Side]];
  483.    Wall.opaque    = 0;
  484.  
  485. /* If there is a main_tx then there will not be an upper
  486.  * or lower, so we can exit when done with this.
  487.  */
  488.  
  489.    if (ThisSide->main_tx[0] != '-') {
  490.       Rb = Pz - floor_ht;
  491.       Rt = Pz - ceiling_ht;
  492.  
  493.       Wall.type   = WALL_TYPE;
  494.       Wall.tex_code = hash(ThisSide, WALL_TYPE);   /* Added by Johan */
  495.       AddWall(sx1, sx2, Rb, Rt, (short)Rfz, (short)Rtz);
  496.  
  497. if (singlestep && (wallopt || flooropt)) {
  498.    c2p(screenbuf, width, height);
  499. }
  500.  
  501.       if (SingleSided) {
  502.          Wall.opaque = 1;
  503. #ifdef COUNT
  504.    loadseg_loops2 += x2 - x1;
  505. #endif
  506.          for(x = x1;x < x2;x++)
  507.             if (Col_Done[x] == 0) {
  508.                ColCount++;
  509.                Col_Done[x] = 1;
  510.             }
  511.       }
  512.       return;
  513.    }
  514.  
  515. /* If there is not a main_tx then there will be both an
  516.  * upper_tx, and a lower_tx.  One or both may have a height of zero.
  517.  */
  518.  
  519.    ThatSide = &Side_Array[ThisLine->side[!Side]];
  520.  
  521.    if (ThisSide->lower_tx[0] != '-')
  522.       Rt = Pz - Sector_Array[ThatSide->sector].floor_ht;
  523.    else
  524.       Rt = Pz - floor_ht;
  525.  
  526.    Rb = Pz - floor_ht;
  527.    Wall.type   = LOWER_TYPE;
  528.    Wall.tex_code = hash(ThisSide, LOWER_TYPE);   /* Added by Johan */
  529.    AddWall(sx1, sx2, Rb, Rt, (short)Rfz, (short)Rtz);
  530.  
  531. if (singlestep && (wallopt || flooropt)) {
  532.    c2p(screenbuf, width, height);
  533. }
  534.  
  535.    if (ThisSide->upper_tx[0] != '-')
  536.       Rb = Pz - Sector_Array[ThatSide->sector].ceiling_ht;
  537.    else
  538.       Rb = Pz - ceiling_ht;
  539.  
  540.    Rt = Pz - ceiling_ht;
  541.    Wall.type   = UPPER_TYPE;
  542.    Wall.tex_code = hash(ThisSide, UPPER_TYPE);   /* Added by Johan */
  543.    AddWall(sx1, sx2, Rb, Rt, (short)Rfz, (short)Rtz);
  544.  
  545. if (singlestep && (wallopt || flooropt)) {
  546.    c2p(screenbuf, width, height);
  547. }
  548. }
  549.  
  550.